package sr.codemg.config;


import io.jsonwebtoken.Claims;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import sr.codemg.utils.Constants;
import sr.codemg.utils.ResponseCode;
import sr.codemg.utils.StaticFunc;
import sr.codemg.utils.TokenManager;
import sr.codemg.vm.Base;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

@Slf4j
@Component
@Aspect
@Order(1)
public class Authorized {
    private static List<String> urls = new ArrayList<>();

    @Autowired
    RedisUtil redisUtil;

    static {
        urls.add("/authorized");
    }

    @Pointcut("execution(* sr.myserver.controller..*(..))")
    private void webAuth() {
    }

    @Around("webAuth()")
    public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();
        String url = request.getServletPath();
        if (urls.contains(url)) {
            return joinPoint.proceed();
        }
        String token = TokenManager.getCookie(request, response, Constants.Authorization);
        Object[] objs = joinPoint.getArgs();
        if (StringUtils.isEmpty(token)) {
            for (Object obj : objs) {
                if (obj instanceof Base.Request) {
                    token = ((Base.Request) obj).getToken();
                    break;
                }
            }
        }
        if (token == null) {
            return ResponseCode.getBase("00403");
        }
        Claims claims;
        claims = JwtConfig.thinning(token);
        if (claims == null) {
            return ResponseCode.getBase("00005");
        }
        long timeout = (new Date().getTime() - claims.getIssuedAt().getTime()) / 1000 / 60;
        if (!"1".equals(claims.get("clientType"))) {
            Base.Response ret = tokenCheck(response, token, claims, timeout, 120, 60);
            if (ret != null) return ret;
        } else {
            Base.Response ret = tokenCheck(response, token, claims, timeout, 24 * 60 * 3, 24 * 60 * 7);
            if (ret != null) return ret;
        }

        Object result = joinPoint.proceed(objs);
        return result;
    }

    /**
     * @param response
     * @param token
     * @param curTime  token 创建了多长时间
     * @param timeout  token 过期时间
     * @param refTtime token 刷新时间
     * @return
     */
    private Base.Response tokenCheck(HttpServletResponse response, String token, Claims claims, long curTime, long timeout, int refTtime) {
        if (curTime > timeout) {
            return ResponseCode.getBase("00004");
        }
        String userId = JwtConfig.getUserId(claims);
        if (timeout > refTtime) {
            redisUtil.del(token);
            String jwtToken = JwtConfig.refresh(claims);
            TokenManager.setCookie(response, Constants.Authorization, jwtToken);
            redisUtil.hset(JwtConfig.getUserId(claims), Constants.USER_CONFIG.JWT_TOKENS, jwtToken);
            redisUtil.set(jwtToken, userId);

        } else if (!token.equalsIgnoreCase(StaticFunc.ons(redisUtil.hget(userId, Constants.USER_CONFIG.JWT_TOKENS)))) {
            return ResponseCode.getBase("00004");
        }
        redisUtil.expire(JwtConfig.getUserId(claims), Constants.USER_CONFIG.CACHE_TIMEOUT);
        redisUtil.expire(token, Constants.USER_CONFIG.CACHE_TIMEOUT);
        return null;
    }

}
